package neves.android.etmg.tilemap;

import java.util.LinkedList;
import neves.android.etmg.map.MapRender;
import neves.android.etmg.sprite.GameSprite;
import neves.android.etmg.sprite.MovableObject;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.Log;

public class TileMapRender implements MapRender {
	
	private TileMap targetMap;
	
	private Bitmap miniMap;

	
    private RectF bgRect;
    private Paint bgRectPaint;
    
    private RectF gridRect;
    private Paint gridPaintA;
    private Paint gridPaintB;
    private Paint gridPaintC;   // for testing
    
    private RectF playerRect;
    private Paint playerPaint;
    
    private Paint miniMapPaint;
    private Paint miniMapSpritePaint;

    
    private int viewHeight = 1;
    private int viewWidth = 1;
    
    
    // the size of the block for the user view (should be odd)
    private int gridSize = 9;
        
    private int centerBlockX = 1;
    private int centerBlockY = 1;
    
    private int originX = 0;
    private int originY = 0;
    
    // the width & hieght of each block
	private int blockWidth = 1;
	private int blockHeight = 1;
    
	private int viewPosAdjX = 0;
	private int viewPosAdjY = 0;
	
    public TileMapRender(){
    	
        SetupPaints();
        
        bgRect = new RectF(0, 0, 1000, 1000);
        
        gridRect = new RectF(0,0,0,0);
        
        playerRect = new RectF(0,0,0,0);
        

        
        
    }
    
    private void SetupPaints(){
        // Initialize paints 
    	bgRectPaint = new Paint();
    	bgRectPaint.setAntiAlias(true);
    	bgRectPaint.setARGB(200, 110, 110, 10);
    	
    	playerPaint = new Paint();
    	//playerPaint.setAntiAlias(true);
    	playerPaint.setARGB(200, 200, 10, 10);
    	
    	gridPaintA = new Paint();
    	gridPaintA.setARGB(255, 255, 255, 255);   	
    	
    	gridPaintB = new Paint();
    	gridPaintB.setARGB(255, 0, 0, 0); 
    	
    	gridPaintC = new Paint();
    	gridPaintC.setARGB(255, 255, 0, 0); 
    	
    	miniMapPaint = new Paint();
    	miniMapPaint.setARGB(50, 0, 255, 0);
    	
    	miniMapSpritePaint = new Paint();
    	miniMapSpritePaint.setARGB(200, 100, 0, 255);
    }
    
    public void SetMap(TileMap tMap){
    	targetMap = tMap;
    	UpdateMiniMap();
    }
    
    
	@Override
	public void DoDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		
    	// repaint the background for clean up
		bgRect.set(0, 0, canvas.getWidth(), canvas.getHeight());
    	canvas.drawRect(bgRect, bgRectPaint);
    	
    	DrawMap(canvas);
    	
    	DrawSprites(canvas);
    	
    	DrawMiniMap(canvas);
    	
    	//playerRect.set(centerBlockX, centerBlockY, centerBlockX+blockWidth, centerBlockY+blockHeight);
    	
    	//canvas.drawText("player",0,1,centerBlockX,centerBlockY,playerPaint);
    	
    	canvas.restore();		
	}
	
	private void DrawSprites(Canvas canvas){
		LinkedList<GameSprite> sprites = targetMap.GetSprites();
		
		int[] onScreenPos ;
		
		int[] curViewPos = AdjustViewPos(targetMap.GetViewer().GetPos());
		
		// paint all sprites in miniMap
		if(sprites!=null){
			
			for(GameSprite curSprite : sprites){
								
				int[] objPos = curSprite.GetPos();
				
				objPos = GetViewRelatedPos(objPos,curViewPos);
				
				if(curSprite.IsVisible() && objPos[0]>=0 && objPos[0]<gridSize && objPos[1]>=0 && objPos[1]<gridSize){
				
					onScreenPos = GetBlockPos(objPos[0],objPos[1]);
				
					//Log.w("ETMG", "Player:"+objPos[0]+","+objPos[1]);

					curSprite.DoDraw(canvas, onScreenPos[0], onScreenPos[1], playerPaint);
				}

				
			}
			
		}
		
	}
	
	private int[] AdjustViewPos(int[] b4pos){
		return new int[]{b4pos[0]-viewPosAdjX,b4pos[1]-viewPosAdjY};
	}
	
	private void DrawMap(Canvas canvas){
    	int[] gridPos;
    	int[] viewLoc = AdjustViewPos(targetMap.GetViewer().GetPos());
    	Paint  tempaint = gridPaintB;
    	
    	for(int tempx = 0;tempx<gridSize;tempx++){
    		for(int tempy = 0;tempy<gridSize;tempy++){
    			
    			// get the grid position align by the center point 
    			gridPos = GetBlockPos(tempx,tempy);
    			
    			switch(targetMap.GetIntTile(viewLoc[0]+tempx, viewLoc[1]+tempy)){

    				case 1:
    					tempaint = gridPaintA;
    					break;
    				case 2:
    					tempaint = gridPaintC;
    					break;
    				
    					
    				default:
    					tempaint = gridPaintB;
    				
    			}
    			gridRect.set(gridPos[0], gridPos[1] , gridPos[0]+blockWidth-1, gridPos[1]+blockHeight-1);
    			canvas.drawRect(gridRect, tempaint);
    		}
    	}
	}
	
	private void DrawGrid(Canvas canvas){
    	int[] originPos;
    	boolean isBlack = true;
    	for(int tempx = 0;tempx<gridSize;tempx++){
    		for(int tempy = 0;tempy<gridSize;tempy++){
    			
    			// get the grid position align by the center point 
    	    	originPos = GetBlockPos(tempx,tempy);
    	    	
    	    	gridRect.set(originPos[0], originPos[1] , originPos[0]+blockWidth-1, originPos[1]+blockHeight-1);
    	    	
    	    	if(isBlack){
    	    		isBlack = false;
    	    		canvas.drawRect(gridRect, gridPaintB);
    	    	}else
    	    	{
    	    		isBlack = true;
    	    		canvas.drawRect(gridRect, gridPaintA);
    	    	}
    	    	
    	    	// draw the x-coordinate text
    	    	canvas.drawText(String.valueOf(tempx),0,1,originPos[0],originPos[1]+10, playerPaint);   			
    		}
    		
    	}		
		
	}


	
	private void DrawMiniMap(Canvas canvas){

		RectF temRF = new RectF(0,0,256,256);
		
		miniMapPaint.setARGB(100, 0, 255, 0);
		
		// paint Map outlay
		canvas.drawBitmap(miniMap, 0, 0, miniMapPaint);
		
		// paint all sprites
		for(GameSprite curSpr : targetMap.GetSprites()){
			
			int[] sprPos = curSpr.GetPos();
			sprPos[0] *=2;
			sprPos[1] *=2;
			
			temRF.set(sprPos[0],sprPos[1],sprPos[0]+2,sprPos[1]+2);
			
			canvas.drawRect(temRF, miniMapSpritePaint);
		}
		
		int[] playerPos = targetMap.GetPlayer().GetPos();
		temRF.set(playerPos[0]*2,playerPos[1]*2,playerPos[0]*2+2,playerPos[1]*2+2);
		canvas.drawRect(temRF, playerPaint);

	}
	
	
	@Override
	public void SetViewSize(int vwidth,int vheight){
		// TODO Auto-generated method stub
		
		viewWidth = vwidth;
		viewHeight = vheight;

		InitialGrid(viewWidth,viewHeight);
		
		UpdateSpriteSize();
	}
	
	protected void UpdateSpriteSize(){
		if(targetMap!=null){
			
			LinkedList<GameSprite> sprites = targetMap.GetSprites();
			
			for(GameSprite curspr : sprites){
				curspr.SetImageSize(blockWidth, blockHeight);
			}
			
			
		}
	}
	
	
	// initial all grid settings
	private void InitialGrid(int vwidth,int vheight){
		blockWidth = (int)((double)vwidth/gridSize);
		blockHeight =  (int)((double)vheight/gridSize);
		
		int viewCenterX = Math.round(vwidth/2);
		int viewCenterY = Math.round(vheight/2);
		
		centerBlockX = viewCenterX - (blockWidth/2);
		centerBlockY = viewCenterY - (blockHeight/2);
		
		int blocksAtLeft = ((gridSize-1)/2);
		
		originX = centerBlockX - (blockWidth*blocksAtLeft);
		originY = centerBlockY - (blockHeight*blocksAtLeft);
		
		viewPosAdjX = (int)((gridSize-1)/2);
		viewPosAdjY = (int)((gridSize-1)/2);
		
		Log.w("ETMG","origin("+originX+","+originY+")");
		
	}
	
	private int[] GetBlockPos(int blockIndexX, int blockIndexY){
		int[] blockPos = new int[2];
		
		blockPos[0] = originX + blockIndexX*blockWidth;
		blockPos[1] = originY + blockIndexY*blockHeight;
		
		return blockPos;
		
	}
	
	private int[] GetViewRelatedPos(int[] actualPos, int[] viewPos){
		return new int[]{actualPos[0]-viewPos[0],actualPos[1]-viewPos[1]};
	}

	@Override
	public MovableObject GetViewSprite() {
		// TODO Auto-generated method stub
		return targetMap.GetPlayer();
	}
	
	private void UpdateMiniMap(){
		
		int[] msize = targetMap.MapSize();
		
        Bitmap temMiniMap = Bitmap.createBitmap(msize[0], msize[1], Bitmap.Config.ARGB_4444);
        
    	Canvas miniCanvas = new Canvas(temMiniMap);
        
        SyncToMiniMap(miniCanvas);
        
        miniMap = temMiniMap.createScaledBitmap(
        		temMiniMap, 256, 256, true);
        
        
        //miniCanvas.save();
        //miniCanvas.restore();
        
        //miniCanvas.drawText("XXXXX", 100, 100, playerPaint);
		
	}
	private void SyncToMiniMap(Canvas minicanvas){
		
		RectF temRF = new RectF(0,0,0,0);
		
		miniMapPaint.setARGB(255, 0, 255, 0);
		
		//canvas.drawRect(temRF, miniMapPaint);
		

		for(TileMapRoom curRoom : targetMap.GetRooms()){
			
			temRF.set(curRoom.Left(), curRoom.Top(), curRoom.Right(), curRoom.Bottom());
				
			minicanvas.drawRect(temRF, miniMapPaint);
		}
		
		for(TileMapRoom curItem : targetMap.GetPassages()){
			
			temRF.set(curItem.Left(), curItem.Top(), curItem.Right(), curItem.Bottom());
			
			minicanvas.drawRect(temRF, miniMapPaint);
		}
		

	}
}
